// BookTableDlg.cpp : implementation file
//

#include "stdafx.h"
#include "BookTable.h"
#include "BookTableDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBookTableDlg dialog

CBookTableDlg::CBookTableDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CBookTableDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CBookTableDlg)
        // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    // load all bitmaps
    m_BookClosed.LoadBitmap(IDB_EXPANDABLE);
    m_BookOpen.LoadBitmap(IDB_EXPANDED);
    m_Topic.LoadBitmap(IDB_LEAF);
    m_Plus.LoadBitmap(IDB_PLUS);
    m_Minus.LoadBitmap(IDB_MINUS);
    m_Plain.LoadBitmap(IDB_PLAIN);
}

void CBookTableDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CBookTableDlg)
    DDX_Control(pDX, IDC_CHECKUSEPLAIN, m_CheckUsePlain);
    DDX_Control(pDX, IDC_CHECKSHOWPLUSMIN, m_CheckPlusMin);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBookTableDlg, CDialog)
    ON_COMMAND(ITEMMENU_ENTRY, OnMenu_ItemMenu_Entry)
    ON_COMMAND(HEADERMENU_SHOWALL, OnMenu_HeaderMenu_ShowAll)
    ON_COMMAND_RANGE(HEADERMENU_IDS+0, HEADERMENU_IDS+99, OnMenu_HeaderMenu_Entry)
    //{{AFX_MSG_MAP(CBookTableDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_CHECKSHOWPLUSMIN, OnCheckShowPlusMinClicked)
    ON_BN_CLICKED(IDC_CHECKUSEPLAIN, OnCheckUsePlainClicked)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBookTableDlg message handlers

BOOL CBookTableDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    m_vTree = GetDlgItem(IDC_SFTTREE1)->GetControlUnknown();
    ASSERT(m_vTree != NULL);

#if 0
    // This shows how to dynamically create a tree control.  If created dynamically,
    // all properties must also be set dynamically.
    CWnd* pTree = new CWnd();
    pTree->CreateControl(_T("SftTreeOCX70.SftTree.1"), _T(""), WS_CHILD|WS_VISIBLE, CRect(0,0,300,300),
                this, 123, NULL, FALSE, NULL);
    m_vTree = pTree->GetControlUnknown();
    ASSERT(m_vTree != NULL);
#endif

    // random numbers
    srand(0);

    m_vTree->BulkUpdate = VARIANT_true; // Mass update

    // set default item graphic.  This can also be done at design time
    m_vTree->Items->ItemImageExpandable->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_BookClosed);
    m_vTree->Items->ItemImageExpanded->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_BookOpen);
    m_vTree->Items->ItemImageLeaf->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Topic);

    // set the column header images (to indicate sorting)
    m_vTree->Header[0]->Image->Appearance = sftImageSortAsc;
    m_vTree->Header[1]->Image->Clear();
    m_vTree->Header[2]->Image->Clear();

    // make a copy of the tree control's font and make a bold
    // font for certain cells
    IFontPtr pFont = m_vTree->GetFont();
    IFontPtr pCellFont;
    HRESULT hr = pFont->Clone(&pCellFont);
    ASSERT(SUCCEEDED(hr));
    pCellFont->put_Bold(TRUE);

    // Add all available options
    for (int bk = 1 ; bk <= 4 ; ++bk) {
        // add a book
        CString str;
        str.Format("Book %d", bk);
        long BookIndex = m_vTree->Items->Add(_bstr_t(str));

        str.Format("Description for book %d", bk);
        m_vTree->Cell[BookIndex][1]->Text = (_bstr_t)str;

        int size = (rand() % 999) + 1;
        str.Format("%d", size);
        m_vTree->Cell[BookIndex][2]->Text = (_bstr_t)str;
        m_vTree->Item[BookIndex]->Data = size;

        // add chapters
        for (int ch = 1 ; ch <= 2 ; ++ch) {
            str.Format("Chapter %d", ch);
            long Index = m_vTree->Items->Add((_bstr_t)str);
            m_vTree->Item[Index]->Level = 1;
            // add sections
            for (int sect = 1 ; sect <= 2 ; ++sect) {
                str.Format("Section %d", sect);
                Index = m_vTree->Items->Add((_bstr_t)str);
                m_vTree->Item[Index]->Level = 2;
            }
        }
        // after adding the book and all dependent items, we
        // collapse the item, so it's up to the user to expand it
        m_vTree->Item[BookIndex]->Collapse(VARIANT_FALSE);
        // set font
        IFontDispPtr pFontDisp = pCellFont;
        m_vTree->Cell[BookIndex][0]->PutFont(pFontDisp);
    }

    // End of Mass-Update
    m_vTree->BulkUpdate = VARIANT_FALSE;

    // Make columns optimal
    m_vTree->ColumnsObj->MakeOptimal();
    // allow horizontal scrolling
    m_vTree->Items->RecalcHorizontalExtent();

    return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBookTableDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CBookTableDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CBookTableDlg::OnCancel() 
{
    CDialog::OnCancel();
}

void CBookTableDlg::OnCheckShowPlusMinClicked() 
{
    if (m_CheckPlusMin.GetCheck()) {
        m_vTree->Items->PlusMinusImageExpandable->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Plus);
        m_vTree->Items->PlusMinusImageExpanded->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Minus);
    } else {
        m_vTree->Items->PlusMinusImageExpandable->Clear();
        m_vTree->Items->PlusMinusImageExpanded->Clear();
    }
}

void CBookTableDlg::OnCheckUsePlainClicked() 
{
    if (m_CheckUsePlain.GetCheck())
        m_vTree->PutButtonPictureH((OLE_HANDLE)(HBITMAP)m_Plain);
    else
        m_vTree->PutButtonPictureH(NULL);
}

void CBookTableDlg::SortHeader(short colIndex) 
{
    if (m_vTree->Header[colIndex]->Image->Appearance == sftImageSortAsc) {
        // Sort the data. Note that column 2 is sorted by Item.Data, which is
        // an integer value (book size in pages)
        if (colIndex == 2)
            m_vTree->Items->SortDependents(-1, colIndex, sortSftTreeDscItemData);
        else
            m_vTree->Items->SortDependents(-1, colIndex, sortSftTreeDescending);
        m_vTree->Header[colIndex]->Image->Appearance = sftImageSortDesc;
    } else {
        m_vTree->Header[0]->Image->Clear();
        m_vTree->Header[1]->Image->Clear();
        m_vTree->Header[2]->Image->Clear();
        // Sort the data. Note that column 2 is sorted by Item.Data, which is
        // an integer value (book size in pages)
        if (colIndex == 2)
            m_vTree->Items->SortDependents(-1, colIndex, sortSftTreeAscItemData);
        else
            m_vTree->Items->SortDependents(-1, colIndex, sortSftTreeAscending);
        m_vTree->Header[colIndex]->Image->Appearance = sftImageSortAsc;
    }
}

void CBookTableDlg::HeaderMenu(CPoint pt)
{
    m_HeaderMenu.DestroyMenu();
    m_HeaderMenu.CreatePopupMenu();

    int count = 0;
    for (short c = 0 ; c < m_vTree->ColumnsObj->Count ; ++c) {

        m_HeaderMenu.AppendMenu(MF_STRING, HEADERMENU_IDS + c, m_vTree->Header[c]->Text);

        if (m_vTree->Column[c]->WidthPix > 0) {
            m_HeaderMenu.CheckMenuItem(HEADERMENU_IDS + c, MF_CHECKED|MF_BYCOMMAND);
            ++count;
        } else
            m_HeaderMenu.CheckMenuItem(HEADERMENU_IDS + c, MF_UNCHECKED|MF_BYCOMMAND);
    }

    if (count <= 1) {
        for (short c = 0 ; c < m_vTree->ColumnsObj->Count ; ++c) {
            if (m_HeaderMenu.GetMenuState(HEADERMENU_IDS + c, MF_CHECKED))
                m_HeaderMenu.EnableMenuItem(HEADERMENU_IDS + c, MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);
            else
                m_HeaderMenu.EnableMenuItem(HEADERMENU_IDS + c, MF_ENABLED|MF_BYCOMMAND);
        }
    }

    m_HeaderMenu.AppendMenu(MF_SEPARATOR);

    m_HeaderMenu.AppendMenu(MF_STRING, HEADERMENU_SHOWALL, _T("&Show All"));
    if (count < m_vTree->ColumnsObj->Count)
        m_HeaderMenu.EnableMenuItem(HEADERMENU_SHOWALL, MF_ENABLED|MF_BYCOMMAND);
    else
        m_HeaderMenu.EnableMenuItem(HEADERMENU_SHOWALL, MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);

    m_vTree->CancelMode();

    m_HeaderMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, this);
}

void CBookTableDlg::ItemMenu(CPoint pt)
{
    m_ItemMenu.DestroyMenu();
    m_ItemMenu.CreatePopupMenu();

    m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Edit"));
    m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Insert"));
    m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Append"));
    m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Delete"));

    m_vTree->CancelMode();

    m_ItemMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, this);
}

void CBookTableDlg::OnContextMenuSftTree1(short Button, short Shift, long x, long y) 
{
    CPoint pt(x, y);
    ::MapWindowPoints((HWND) m_vTree->hWnd, NULL, &pt, 1);

    // Determine click context menu for header or item
    long l, t, w, h;
    m_vTree->Headers->GetPositionPix(&l, &t, &w, &h);
    if (x >= l && x < l + w && y >= t && y <= t + h) {
        HeaderMenu(pt);
        return;
    }
    
    // determine item right-clicked
    long ItemIndex;
    ItemIndex = m_vTree->Items->HitTestPix(x, y);
    if (ItemIndex >= 0 && ItemIndex < m_vTree->Items->Count) {
        m_vTree->Items->Current = ItemIndex;
        m_vTree->Item[ItemIndex]->Selected = VARIANT_true;
        ItemMenu(pt);
        return;
    }
}

void CBookTableDlg::OnItemClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeColumnHeader && Button == constSftTreeLeftButton)
        SortHeader(ColIndex);
    else if (AreaType == constSftTreeExpandAll)
        m_vTree->Item[ItemIndex]->Expand(VARIANT_FALSE, VARIANT_true);
}

void CBookTableDlg::OnItemDblClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) 
{
    if (AreaType == constSftTreeColumnRes && Button == constSftTreeLeftButton) {
        m_vTree->Column[ColIndex]->MakeOptimal();
        m_vTree->Items->RecalcHorizontalExtent();
    } else if (AreaType == constSftTreeColumnHeader && Button == constSftTreeLeftButton)
        SortHeader(ColIndex);
}

afx_msg void CBookTableDlg::OnMenu_ItemMenu_Entry()
{
    AfxMessageBox(_T("This sample doesn't implement any actions for the item menu.  Try the column headers instead."));
}

afx_msg void CBookTableDlg::OnMenu_HeaderMenu_ShowAll()
{
    m_vTree->ColumnsObj->MakeOptimal();
}

afx_msg void CBookTableDlg::OnMenu_HeaderMenu_Entry(UINT nID)
{
    short colIndex = (short) (nID - HEADERMENU_IDS);
    if (m_HeaderMenu.GetMenuState(nID, MF_CHECKED))
        m_vTree->Column[colIndex]->WidthPix = 0;
    else
        m_vTree->Column[colIndex]->MakeOptimal();
    m_vTree->Items->RecalcHorizontalExtent();
}

BEGIN_EVENTSINK_MAP(CBookTableDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CBookTableDlg)
    ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 35 /* ContextMenu */, OnContextMenuSftTree1, VTS_I2 VTS_I2 VTS_I4 VTS_I4)
    ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 4 /* ItemClick */, OnItemClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 5 /* ItemDblClick */, OnItemDblClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()